/*
 * @(#)ShellExtension.java	1.0 Apr 26, 2008
 *
 *	The MIT License
 *
 *	Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 */
package org.eoti.io.console.shell;

import org.eoti.io.console.Terminal;
import org.eoti.util.size.Bytes;
import org.eoti.util.CollectionUtil;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.util.*;
import java.text.SimpleDateFormat;
import java.math.BigInteger;

public abstract class ShellExtension
implements PropertyChangeListener
{
	protected List<Bytes> sizes;
	protected Shell shell;
	private int consoleWidth = -1;
	private String fmt;
	protected SimpleDateFormat sdf;

	public ShellExtension()
	{
		sizes = CollectionUtil.reverse(Bytes.values());
		sdf = new SimpleDateFormat("ddMMMyy hh:mm:ss aa zzz");
	}
	public void setShell(Shell shell)
	{
		this.shell = shell;
		computeWidth();
	}
	public Shell getShell(){return shell;}

	protected String date(Date date)
	{
		return sdf.format(date);
	}
	protected String size(long bytes)
	{
        return Bytes.friendly(bytes);
	}

	protected void computeWidth()
	{
		if(shell == null) return;
		this.consoleWidth = shell.getConsoleWidth();
		computeFormat();
	}
	public int getConsoleWidth(){return consoleWidth;}
	protected void setFormat(String fmt){this.fmt = fmt;}
	public String getFormat(){return fmt;}

	protected void computeFormat()
	{
		fmt = "%s\n";
	}

	protected String defaultFormat(int width)
	{
		if(width <= 0) throw new IllegalArgumentException("Width must be >0");
		return "%-"+width+"."+width+"s";
	}

	public void format(Object ... values)
	{
		shell.format(fmt, values);
	}

	public void propertyChange(PropertyChangeEvent evt)
	{
		if(evt.getPropertyName().equals(Terminal.DefinedEnv.consoleWidth.toString()))
			computeWidth();
	}

	/**
	 * Executes the shell extension with the specified arguments
	 * @param arguments to pass to the extension
	 * @throws org.eoti.io.console.shell.ShellException on any error
	 */
	public abstract void execute(List<String> arguments) throws ShellException;

	/**
	 * @return name the shell extension wishes to register under
	 */
	public abstract String getName();

	/**
	 * @return simple usage instructions
	 */
	public String getUsage(){return getName();}

	/**
	 * detailed instructions
	 */
	public void manual()
	{
		shell.format("%s\n", getUsage());
	}

	protected void error(String msg, boolean showStackTrace) throws ShellException
	{
		throw new ShellException(shell, this, msg, showStackTrace);
	}

	protected void error(String msg) throws ShellException
	{
		throw new ShellException(shell, this, msg, false);
	}

	protected void error(String msg, Throwable cause, boolean showStackTrace) throws ShellException
	{
		throw new ShellException(shell, this, msg, cause, showStackTrace);
	}

	protected void error(String msg, Throwable cause) throws ShellException
	{
		throw new ShellException(shell, this, msg, cause, true);
	}

	protected void error(Throwable cause, boolean showStackTrace) throws ShellException
	{
		throw new ShellException(shell, this, cause, showStackTrace);
	}

	protected void error(Throwable cause) throws ShellException
	{
		throw new ShellException(shell, this, cause, true);
	}

	protected void error(String fmt, Object ... args) throws ShellException
	{
		throw new ShellException(shell, this, String.format(fmt, args), false);
	}

	protected void error(Throwable cause, String fmt, Object ... args) throws ShellException
	{
		throw new ShellException(shell, this, String.format(fmt, args), cause, true);
	}
}
